package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"

	"unsafe"

	"github.com/360EntSecGroup-Skylar/excelize"

	"net"
	"strings"
	"sync"
	"syscall"

	"github.com/axgle/mahonia"
	"github.com/google/uuid"
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
	"github.com/panjf2000/ants/v2"

	"iot-base/common/dbconn"
	"net/http"
	"path/filepath"

	//"strings"
	"time"
)

func online(id string, isOnline bool, ip string, dtype string, onLineMap *sync.Map) {

	onLineMap.Store(id, State{
		IsOnline: isOnline,
		DType:    dtype,
		IP:       ip,
	})

}

func makeFun(id, ip string, mode string, onLineMap *sync.Map) func() {

	if mode == "http" {
		return func() {
			checkWithHttp(id, ip, onLineMap)
		}
	}
	return nil

}

func beginCheck(id, ip string, onLineMap *sync.Map) {
	//fmt.Printf("begin adding running goroutines: %d\n", ants.Running())
	ants.Submit(makeFun(id, ip, "http", onLineMap))
	//fmt.Printf("finish adding running goroutines: %d\n", ants.Running())

}

func check(id, ip string) (string, error) {
	timeout := time.Duration(2) * time.Second
	client := http.Client{
		Timeout: timeout,
	}
<<<<<<< HEAD

	resp, err := client.Get("http://" + ip)

=======
	resp, err := client.Get(ip)
	if id == "1122" {
		fmt.Println("*http***********1122****end**", err, ip)
	}
>>>>>>> 6e0d288c7762dac5343d82b5b0a99402a794a7e0
	var dtype = "UNKNOWN"
	if resp != nil {
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err == nil {
			//b := string(body)
			b := mahonia.NewDecoder("gbk").ConvertString(string(body))
			if strings.Contains(b, "WebCam Mon") {
				dtype = "BOX"
			} else {
				dtype = "其他设备"
				//strC := []rune(b)
				begin := strings.Index(b, "<title>")
				if begin >= 0 {

					end := strings.Index(b, "</title>")
					if end >= 0 {
						detail := b[begin+7 : end]
						dtype = dtype + ":" + detail

					}
				}
			}
		} else {
			dtype = "error:" + err.Error()
		}
	} else {
		dtype = ip + "not response"
	}
	return dtype, err

}

<<<<<<< HEAD
	online(id, err == nil, ip, dtype, onLineMap)
=======
func checkWithHttp(id, ip string, onLineMap *sync.Map) {

	if id == "1122" {
		fmt.Println("*http***********1122****begin**")
	}
	var err error
	var dtype string
	for i := 0; i < 20; i++ {
		dtype, err = check(id, ip)
		if err == nil {
			break
		}
	}
	online(id, err == nil, dtype, onLineMap)
>>>>>>> 6e0d288c7762dac5343d82b5b0a99402a794a7e0
	wg.Done()

}

func init() {
	beginPool()
}

func beginPool() {
	ants.NewPool(100)
}

//func main() {
// f, err := excelize.OpenFile("d:/checkfile/exportempty.xlsx")
// if err != nil {
// 	fmt.Println(err)
// 	return
// }

// rows := f.GetRows("Sheet1")
// for i, row := range rows {
// 	if i >= 2 {
// 		if row[3] == nil || row[3] == "" {
// 			f.SetCellValue("Sheet1")
// 		}
// 	}

// }

type MyMainWindow struct {
	*walk.MainWindow
	edit *walk.TextEdit

	path string
}

type IPID struct {
	IP string
	//RIP string
	TID string
}

type IPState struct {
	TID   string
	State string
	IP    string
	UID   string
}

func main() {
	readDevs()
	mw := &MyMainWindow{}
	MW := MainWindow{
		AssignTo: &mw.MainWindow,
		//Icon:     "test.ico",
		Title:   "文件选择对话框",
		MinSize: Size{150, 200},
		Size:    Size{300, 400},
		Layout:  VBox{},
		Children: []Widget{
			TextEdit{
				AssignTo: &mw.edit,
			},
			PushButton{
				Text:      "打开",
				OnClicked: mw.pbClicked,
			},
		},
	}
	if _, err := MW.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

}

type State struct {
	IsOnline bool
	DType    string
	IP       string
}

func (mw *MyMainWindow) pbClicked() {

	dlg := new(walk.FileDialog)
	dlg.FilePath = mw.path

	dlg.Title = "Select File"
	dlg.Filter = "excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*"

	if ok, err := dlg.ShowOpen(mw); err != nil {
		mw.edit.AppendText("Error : File Open\r\n")
		return
	} else if !ok {
		mw.edit.AppendText("Cancel\r\n")
		return
	}
	mw.path = dlg.FilePath
	s := fmt.Sprintf("Select : %s\r\n", mw.path)
	mw.edit.AppendText(s)
	mw.check(mw.path)
}

var wg sync.WaitGroup

func ReadDtEx(conn net.Conn) ([]byte, error) {
	if conn == nil {
		return nil, errors.New("conn is nil")
	}
	var size = 8196
	var buf []byte

	for {
		tmp := make([]byte, size)
		conn.SetReadDeadline(time.Now().Add(1 * time.Second))
		//fmt.Println("-----------------------1", size)
		n, err := conn.Read(tmp)
		if err == io.EOF {
			return buf, err
		}
		//fmt.Println("-----------------------2", size)
		if buf == nil {
			buf = tmp[:n]
		} else {
			buf = append(buf, tmp[:n]...)
		}
		if n < size || err != nil {
			//return buf, err
			break
		}
		size = size * 2
	}
	return buf, nil

}

type AlarmEvent struct {
	REQ string
	Ok  []AlarmDev
}

type AlarmDev struct {
	UID string
	Eve []string
}

type Sbzt struct {
	sbbh   string
	gmzt   string
	sbzt   string
	sdzt   string
	zhgxsj string
}

func getEventsFromJiekou() map[string]Sbzt {
	sbztMap := make(map[string]Sbzt)
	srows, _ := dbconn.DBConnection.Raw(`select sbbh,gmzt,sbzt,sdzt,zhgxsj from sbxxb s`).Rows()
	defer srows.Close()
	for srows.Next() {
		var sbzt Sbzt
		srows.Scan(&sbzt.sbbh, &sbzt.gmzt, &sbzt.sbzt, &sbzt.sdzt, &sbzt.zhgxsj)
		sbztMap[sbzt.sbbh] = sbzt
	}
	return sbztMap

}

func getEvents() map[string]string {
	alarmconn, _ := net.DialTimeout("tcp", "127.0.0.1:37125", 3*time.Second)
	if alarmconn == nil {
		//logger.SLog.Error("connet dev retry error", err)

		return nil
	}

	alarmconn.Write([]byte(`{"REQ":"GetEvent","Dev":[{"UID":"All"}]}\r\n`))
	rd, _ := ReadDtEx(alarmconn)

	var AlarmD AlarmEvent
	jerr := json.Unmarshal(rd, &AlarmD)
	if jerr == nil {
		eveMap := make(map[string]string)
		for _, eve := range AlarmD.Ok {
			eveMap[eve.UID] = strings.Join(eve.Eve, ",")
		}
		return eveMap
	}
	return nil

}

var ipStateMap map[string]IPState

func readDevs() {
	//var pofflines []IPState
	rows, _ := dbconn.DBConnection.Raw(`select t_id,alarm_id from alarm_states ass where ass.is_alarm and 
	ass.alarm_id in ('offline','powerOffline') 
	and is_hide = false order by t_id`).Rows() //Scan(&pofflines)
	defer rows.Close()
	mapPOffline := make(map[string]string)
	for rows.Next() {
		//var state IPState
		var tid, aid string
		rows.Scan(&tid, &aid)
		//pofflines = append(pofflines,state )
		mapPOffline[tid] = aid
	}

	var ipStates []IPState
	irows, _ := dbconn.DBConnection.Raw(`select tp.thing_id TID,tp.param_value IP,tp2.param_value UID from thing_params tp
	left join thing_params tp2 on tp2.thing_id = tp.thing_id and tp2.param_id = 'UID'
	where tp.param_id = 'IP' `).Rows()
	fmt.Println("---------", len(ipStates))
	defer irows.Close()
	ipStateMap = make(map[string]IPState)
	for irows.Next() {
		var state IPState
		irows.Scan(&state.TID, &state.IP, &state.UID)
		//pofflines = append(pofflines,state )
		aid, ok := mapPOffline[state.TID]
		if ok {
			state.State = aid

		} else {
			state.State = "online"
		}
		ipStateMap[state.IP] = state
	}

}
func (mw *MyMainWindow) check(fpath string) {
	u1, _ := uuid.NewUUID()

	fdir, fname := filepath.Split(fpath)
	fmt.Println("*************", fpath, fdir, fname)
	//fname := path.Base(fpath)
	filename := fdir + "\\result_" + filepath.Base(fname) + "_" + u1.String() + ".xlsx"
	mw.edit.AppendText(filename + "\r\n")
	sf, _ := os.Open(fpath)
	df, _ := os.Create(filename)
	defer df.Close()
	defer sf.Close()
	io.Copy(df, sf)

	f, err := excelize.OpenFile(filename)
	mw.edit.AppendText("5%\r\n")
	if err != nil {
		fmt.Println("open-----------error---", err)
		mw.edit.AppendText("error\r\n")
		mw.edit.AppendText(err.Error())
		return
	}
	var onlineMap sync.Map
	rows := f.GetRows("Sheet1")
	mapIP := make(map[string]bool)
	for i, row := range rows {
		if i >= 1 {
			errorGrid := fmt.Sprintf("R%d", i+1)
			typeGrid := fmt.Sprintf("%d", i+1)
			if row[3] == "" {

				f.SetCellValue("Sheet1", errorGrid, "ip地址为空")
				continue
			}
			ip := row[3]
			_, ok := mapIP[ip]
			if ok {
				f.SetCellValue("Sheet1", errorGrid, "ip地址重复")
			} else {
				wg.Add(1)
				beginCheck(typeGrid, ip, &onlineMap)
			}

		}
	}

	mw.edit.AppendText("65%\r\n")
	wg.Wait()

	mapPro := getEvents()
	mapJiekou := getEventsFromJiekou()
	onlineMap.Range(func(k, v interface{}) bool {
		row := k.(string)
		state, ok := v.(State)
		if ok {
			if state.IsOnline {
				if state.DType == "BOX" {
					f.SetCellValue("Sheet1", "S"+row, "OK")
				} else {
					f.SetCellValue("Sheet1", "S"+row, "NOTBOX")
				}

				f.SetCellValue("Sheet1", "T"+row, state.DType)
			} else {
				f.SetCellValue("Sheet1", "S"+row, "连接失败")
			}
			stateInDB, ok := ipStateMap[state.IP]

			if !ok {
				f.SetCellValue("Sheet1", "M"+row, "数据库中无此ip")
			} else {
				f.SetCellValue("Sheet1", "P"+row, "UID:"+stateInDB.UID)
				if stateInDB.State == "offline" {
					f.SetCellValue("Sheet1", "M"+row, "数据库:断网 "+stateInDB.State)
				} else if stateInDB.State == "powerOffline" {
					f.SetCellValue("Sheet1", "M"+row, "数据库:断电 "+stateInDB.State)
				} else {
					f.SetCellValue("Sheet1", "M"+row, "数据库:在线 "+stateInDB.State)
				}
			}
			s := mapPro[stateInDB.UID]
			f.SetCellValue("Sheet1", "N"+row, "中间件:"+s)
			jk, okj := mapJiekou[stateInDB.IP]
			if okj {
				js := fmt.Sprintf("gm:%s szt:%s sdzt:%s time:%s", jk.gmzt, jk.sbzt, jk.sdzt, jk.zhgxsj)
				f.SetCellValue("Sheet1", "O"+row, "接口:"+js)
			} else {
				f.SetCellValue("Sheet1", "O"+row, "接口:无数据")
			}

		} else {
			f.SetCellValue("Sheet1", "S"+row, "连接失败")
		}
		return true
	})
	f.Save()
	//mw.edit.AppendText("100%")
	mw.edit.AppendText("100%\r\n")

	shell32 := syscall.NewLazyDLL("shell32.dll")
	ShellExecuteW := shell32.NewProc("ShellExecuteW")
	var hand uintptr = uintptr(0)
	var operator uintptr = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("open")))
	var fpathw uintptr = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename)))
	var param uintptr = uintptr(0)
	var dirpath uintptr = uintptr(0)
	var ncmd uintptr = uintptr(1)
	_, _, _ = ShellExecuteW.Call(hand, operator, fpathw, param, dirpath, ncmd)

}
